/**
 * DESCRIPTION:CGI COMMON IMPLEMENT FILE
 *  UPDATETIME:2013.10.8/2013.11.12/2013.11.27/2014.03.29
 *   DEVELOPER:
 * REVISETIMES:1/2/3/4/5
 *  CREATETIME:2013.7.30
 */

#include "cgi.h"

namespace cppcgi
{

int error_code = 0;
const string env[] = {"REMOTE_ADDR","DOCUMENT_ROOT",
    "GATEWAY_INTERFACE","SERVER_SOFTWARE","SERVER_NAME",
    "SERVER_PROTOCOL","SERVER_PORT","SERVER_ADMIN","SERVER_SIGNATURE",
    "REQUEST_METHOD","REQUEST_URI","PATH_INFO","PATH_TRANSLATED",
    "SCRIPT_NAME","SCRIPT_FILENAME","QUERY_STRING","REMOTE_HOST",
    "REMOTE_USER","REMOTE_IDENT","CONTENT_TYPE","CONTENT_LENGTH",
    "HTTP_ACCEPT","HTTP_ACCEPT_CHARSET","HTTP_ACCEPT_LANGUAGE",
    "HTTP_ENCODING","HTTP_USER_AGENT","HTTP_CONNECTION","HTTP_HOST",
    "HTTP_REFERER","HTTP_COOKIE","AUTH_TYPE","HTTPS",""};

static string scriptName = "";
static bool isHeadSetted = false;

#ifndef __notcgi
CppCgi cppcgi_global;
#endif

string SimplePath(const string& str)
{
    size_t pos;
    pos = str.rfind("/");
    if (pos != string::npos)
        return str.substr(pos + 1, str.size() - pos - 1);
    else
    {
        pos = str.rfind("\\");
        if (pos != string::npos)
            return str.substr(pos + 1, str.size() - pos - 1);
        else
           return str;
    }
}

void InitFunc(const string& str)
{
    scriptName = SimplePath(str);
}
/**
 *
 */
string GetEnv(const string& param)
{
    //CGILOG(INFO);
    char *paramAsChar = getenv(param.c_str());
    return paramAsChar ? paramAsChar : "";
    //CGILOG(INFO);
}
/**
 *
 */
string ToUpperCase(const string& s)
{
    //CGILOG(INFO);
    string ret;
    int len = s.length();
    for (int i = 0; i < len; i++)
    {
        if (s[i] >= 'a' && s[i] <= 'z')
        {
            ret += s[i] - 32;
        }
        else
        {
            ret += s[i];
        }
    }
    //CGILOG(INFO);
    return ret;
}
string ToLowCase(const string& s)
{
    //CGILOG(INFO);
    string ret;
    int len = s.length();
    for (int i = 0; i < len; i++)
    {
        if (s[i] >= 'A' && s[i] <= 'Z')
        {
            ret += s[i] + 32;
        }
        else
        {
            ret += s[i];
        }
    }
    //CGILOG(INFO);
    return ret;
}

string ToProperCase(const string& s)
{
    string ret;
    if (s[0] >= 'a' && s[0] <= 'z')
        ret += s[0] - 32;
    else
        ret += s[0];
    int len = s.length();
    for (int i = 1; i < len; i++)
        ret += s[i];
    return ret;
}

void Print(const string str)
{
    File* f = File::Open("t", "a");
    f->AddLine(str);
    f->Save();
}

/**
 *
 */
string GetFormatTime()
{
    time_t rawtime;
    struct tm * timeinfo;
    struct timeval now_u;
    char buf1[LINE_LENGTH_64];
    char buf2[LINE_LENGTH_64];
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(buf1, LINE_LENGTH_64, "%Y.%m.%d %H:%M:%S", timeinfo);
    gettimeofday(&now_u, NULL);
    int len = snprintf(buf2, LINE_LENGTH_64, "%s.%d", buf1, (int)now_u.tv_usec);
    buf2[len] = '\0';
    return string(buf2);
}
/**
 *
 */
void ReplaceStr(string& str,
    const string& searchString,
    const string& replaceString)
{
    //CGILOG(INFO);
    string::size_type pos = 0;
    while ((pos = str.find(searchString, pos)) != string::npos)
    {
        str.replace( pos, searchString.size(), replaceString.c_str(), replaceString.size());
        pos += replaceString.size();
    }
    //CGILOG(INFO);
}

/**
 * shan chu zi fu chuan liang bian de kong ge
 */
void Trim(string& s)
{
    //CGILOG(INFO);
    int len = s.length();
    int i, j = 0;
    for (i = 0; i < len; i++)
    {
        if (s[i] == ' ' || s[i] == '\r' || s[i] == '\n')
        {
            continue;
        }
        else
        {
            break;
        }
    }

    for (j = len - 1; j > i; j--)
    {
        if (s[j] == ' ' || s[j] == '\r' || s[j] == '\n')
        {
            continue;
        }
        else
        {
            break;
        }
    }
    s = s.substr(i, 1 + j - i);
    //CGILOG(INFO);
}
/**
 *
 */
void Head()
{
    if (!isHeadSetted)
    {
        cout << "Content-Type:text/html; charset=utf-8" << endl << endl;
        isHeadSetted = true;
    }
}
/**
 *
 */
void Head(const string& type)
{
    if (!isHeadSetted)
    {
        cout << "Content-Type:" << type << "; charset=utf-8" << endl << endl;
        isHeadSetted = true;
    }
}

char* CharSplit(char* s, const char* delim, char** lasts)
{
    //CGILOG(INFO);
    const char* spanp;
    int c, sc;
    char* tok;

    /* s may be NULL */
    /*assert(delim != NULL);*/
    /*assert(lasts != NULL);*/

    if (s == NULL && (s = *lasts) == NULL)
        return (NULL);

    /*
        * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
        */
cont:
    c = *s++;
    for (spanp = delim; (sc = *spanp++) != 0;)
    {
        if (c == sc)
            goto cont;
    }

    if (c == 0)
    {
        /* no non-delimiter characters */
        *lasts = NULL;
        return (NULL);
    }
    tok = s - 1;

    /*
        * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
        * Note that delim must have one NUL; we stop if we see that, too.
        */
    for (;;)
    {
        c = *s++;
        spanp = delim;
        do
        {
            if ((sc = *spanp++) == c)
            {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                *lasts = s;
                return (tok);
            }
        } while (sc != 0);
    }
    /* NOTREACHED */
    //CGILOG(INFO);
}

KvVector KvVector::StrSplit(const string& context,
    const string& str_delim,
    const string& kv_delim)
{
    //CGILOG(INFO);
    char* buf = NULL;
    char* kv = NULL;
    char* outer_ptr = NULL;
    char* inner_ptr = NULL;
    KvVector prop;

    if (context.empty())
    {
        return prop;
    }
    buf = (char*)context.c_str();
    while ((kv = CharSplit(buf, str_delim.c_str(), &outer_ptr)) != NULL)
    {
        char* key = NULL;
        char* value = NULL;

        if ((key = CharSplit(kv, kv_delim.c_str(), &inner_ptr)) != NULL)
        {
            if ((value = CharSplit(NULL, kv_delim.c_str(), &inner_ptr)) == NULL)
            {
                prop.Insert(key, "");
            }
            else
            {
                prop.Insert(key, value);
            }
        }
        buf = NULL;
    }
    //CGILOG(INFO);
    return prop;
}

KvVector KvVector::UrlSplit(const string& context)
{
    //CGILOG(INFO);
    char *buf = NULL;
    char *kv = NULL;
    char *outer_ptr = NULL;
    char *inner_ptr = NULL;

    const string str_delim = "&";
    const string kv_delim = "=";

    KvVector prop;

    if (context.empty())
    {
        return prop;
    }
    buf = (char*)context.c_str();
    while ((kv = CharSplit(buf, str_delim.c_str(), &outer_ptr)) != NULL)
    {
        char* key = NULL;
        char* value = NULL;

        if ((key = CharSplit(kv, kv_delim.c_str(), &inner_ptr)) != NULL)
        {
            if (strcmp(key, "/") == 0)
            {
                break;
            }
            if ((value = CharSplit(NULL, kv_delim.c_str(), &inner_ptr)) == NULL)
            {
                prop.Insert(key, "");
            }
            else
            {
                prop.Insert(key, DecodeUrlComponent(value));
            }
        }
        buf = NULL;
    }
    //CGILOG(INFO);
    return prop;
}
/**
 *
 */
string DecodeUrlComponent(const string& value)
{
    //CGILOG(INFO);
    int k = 0;
    int b = value.length();
    string s;
    const char* url = value.c_str();
    char* changeto = (char*)malloc(b + 1);
    for (int i = 0; ; i++, k++)
    {
        if (url[i] == 0)
        {
            changeto[k] = '\0';
            break;
        }
        else if (url[i] != '%')
        {
            if (url[i] == '+')
            {
                changeto[k] = ' ';
            }
            else
            {
                changeto[k] = url[i];
            }
        }
        else
        {
            char t[20] = {0};
            for (int j = 0; url[j + i + 1] != '%' && url[j + i + 1] != 0; j++)
            {
                t[j] = url[i + j + 1];
                if (j == 1)
                {
                    break;
                }
            }
            char m[3] = {0};
            sscanf(t, "%[0-9A-Fa-f]", m);
            unsigned int hex;
            hex = HexChar2Int(m);
            if (hex != 0)
            {
                changeto[k] = hex;
                if (m[1] == 0)
                {
                    i = i + 1;
                }
                else
                {
                    i = i + 2;
                }
            }
        }
    }
    s = string(changeto);
    free(changeto);
    //CGILOG(INFO);
    return s;
}

unsigned int HexChar2Int(const char* s)
{
    //CGILOG(INFO);
    unsigned int i, m, n, temp = 0;
    m = strlen(s);
    for (i = 0; i < m; i++)
    {
        if (s[i] >= 'A' && s[i] <= 'F')
        {
            n = s[i] - 'A' + 10;
        }
        else if (s[i] >= 'a' && s[i] <= 'f')
        {
            n = s[i] - 'a' + 10;
        }
        else
        {
            n = s[i] - '0';
        }
        temp = temp * 16 + n;
    }
    //CGILOG(INFO);
    return temp;
}

/**
 *
 */
void CopyChar(char*& dst, const char* src, int len)
{
    //CGILOG(INFO);
    dst = (char*)malloc(len + 1);
    memcpy(dst, src, len);
    dst[len] = 0;
    //CGILOG(INFO);
}

/**
 * buf[i] ==> if(buf[i] != 0)
 */
int FindMatch(const char* buf, const char* src)
{
    //CGILOG(INFO);
    int i = 0;
    int srclen;
    srclen = strlen(src);
    for (i = 0; buf[i] && buf[i] != '\r' && buf[i] != '\n'; i++)
    {
        if (strncmp(buf + i, src, srclen) == 0 )
        {
            //CGILOG(INFO);
            return i;
        }
    }
    //CGILOG(INFO);
    return -1;
}
/**
 *
 */
int FindMatchAll(const char* buf, const char* src, int maxoffset)
{
    //CGILOG(INFO);
    int i = 0;
    int srclen;
    srclen = strlen(src);
    for (i = 0; i < maxoffset; i++)
    {
        if (memcmp(buf + i, src, srclen) == 0)
        {
            //CGILOG(INFO);
            return i;
        }
    }
    //CGILOG(INFO);
    return -1;
}

int SaveToFile(const char* buf, const char* file, int length)
{
    FILE* stream;
    if ((stream = fopen(file, "wb")) == NULL)
    {
        CLOG(ERROR) << file << " fopen(wb) error:" << strerror(errno) << endl;
        return -1;
    }
    int ret = 0;
    if (1 != (ret = fwrite(buf, length, 1, stream)))
    {
        CLOG(ERROR) << file << " fwrite error:" << strerror(errno) << endl;
    }
    fclose(stream);
    return 0;
}

/**
 *
 */
string CheckFirst(bool& tag, const string& s)
{
    if (tag)
    {
        tag = 0;
        return "";
    }
    else
    {
        return s;
    }
}
/**
 * string zhuan huan json string qian de zhun bei
 */
string PreJsonStr(string& str)
{
    ReplaceStr(str, "\\", "\\\\");
    ReplaceStr(str, "\"", "\\\"");
    return str;
}

/**
 *
 */
bool PropToJson(KvMap& prop, string& json)
{
    bool firstTag = 1;
    kvmap propMap = prop.Dump();
    kvmap::iterator it;
    if (propMap.size() == 0)
        json = "null";
    else
    {
        json += "{";
        for (it = propMap.begin(); it != propMap.end(); it++)
        {
            json += CheckFirst(firstTag, ",");
            string s = it->second;
            ReplaceStr(s, "\\", "\\\\");
            ReplaceStr(s, "\"", "\\\"");
            json += "\"" + it->first + "\":\"" + s + "\"";
        }
        json += "}";
    }
    return true;
}

bool PropToJson(KvVector& prop, string& json)
{
    bool firstTag = 1;
    int len = prop.Size();

    if (len == 0)
        json = "null";
    else
    {
        json += "{";
        for (int i = 0; i < len; i++)
        {
            json += CheckFirst(firstTag, ",");
            string s = prop.GetValue(i);
            ReplaceStr(s, "\\", "\\\\");
            ReplaceStr(s, "\"", "\\\"");
            json += "\"" + prop.GetKey(i) + "\":\"" + s + "\"";
        }
        json += "}";
    }
    return true;
}
/**
 *
 */
bool MultiPropToJson(mkvmap&, string&)
{
    return true;
}
/**
 *
 */
void Log(const string& msg)
{
    FILE* stream = fopen(CGILOGFILE, "a+");
    string nowtime = GetFormatTime();
    fprintf(stream, ("[" + nowtime + "] " + msg + "\r\n").c_str());
    fclose(stream);
}

int GetStrChar(char** lineptr,
    size_t* n,
    FILE* stream,
    char terminator,
    int offset)
{
    //CGILOG(INFO);
    int nchars_avail;       /* Allocated but unused chars in *LINEPTR.  */
    char* read_pos;     /* Where we're reading into *LINEPTR. */
    int ret;

    if (!lineptr || !n || !stream)
    {
        errno = EINVAL;
        return -1;
    }

    if (!*lineptr)
    {
        *n = LINE_LENGTH_64;
        *lineptr = (char*)malloc(*n);
        if (!*lineptr)
        {
            errno = ENOMEM;
            return -2;
        }
    }

    nchars_avail = *n - offset;
    read_pos = *lineptr + offset;

    for (;;)
    {
        int save_errno;
        register int c = getc(stream);

        save_errno = errno;

        /* We always want at least one char left in the buffer, since we
        always (unless we get an error while reading the first char)
        NUL-terminate the line buffer.  */

        assert((*lineptr + *n) == (read_pos + nchars_avail));
        if (nchars_avail < 2)
        {
            if (*n > LINE_LENGTH_64)
            {
                *n *= 2;
            }
            else
            {
                *n += LINE_LENGTH_64;
            }

            nchars_avail = *n + *lineptr - read_pos;
            *lineptr = (char*)realloc(*lineptr, *n);
            if (!*lineptr)
            {
                errno = ENOMEM;
                return -3;
            }
            read_pos = *n - nchars_avail + *lineptr;
            assert((*lineptr + *n) == (read_pos + nchars_avail));
        }

        if (ferror(stream))
        {
        /* Might like to return partial line, but there is no
            place for us to store errno.  And we don't want to just
            lose errno.  */
            errno = save_errno;
            return -4;
        }

        if (c == EOF)
        {
            /* Return partial line, if any.  */
            if (read_pos == *lineptr)
            {
                return -5;
            }
            else
            {
                break;
            }
        }

        *read_pos++ = c;
        nchars_avail--;

        if (c == terminator)
        {
        /* Return the line.  */
            break;
        }
    }

    /* Done - NUL terminate and return the number of chars read.  */
    *read_pos = '\0';

    ret = read_pos - (*lineptr + offset);

    return ret;
}

int GetLineChar(char** lineptr,
    size_t* n,
    FILE* stream)
{
    /**
     * bu zhi chi mac X \r jie wei de wen jian
     */
    //CGILOG(INFO);
    return GetStrChar(lineptr, n, stream, '\n', 0);
}

Cookie::Cookie()
{

}

Cookie::~Cookie()
{

}

void Cookie::Add(const string& name, const string& value)
{
    cookieStr_ += "Set-Cookie: " + name + "=" + value + "\r\n";
}

KvMap Cookie::Get()
{
    string cookieStr = GetEnv("HTTP_COOKIE");
    KvVector cookieForm = KvVector::StrSplit(cookieStr, ";", "=");
    int i;
    KvMap cookieMap;
    string key;
    string value;
    for (i = 0; i < cookieForm.Size(); i++)
    {
        key = cookieForm.GetKey(i);
        value = cookieForm.GetValue(i);
        Trim(key);
        Trim(value);
        cookieMap.Insert(key, value);
    }
    return cookieMap;
}

void Cookie::Out()
{
    cout << cookieStr_ << endl;
}

/*
   CITE:
   cgic 2.02: simpler and more widely compatible implementation.
    Thanks to Chunfu Lai.
   cgic 2.03: yes, but it didn't work. Reimplemented by
    Thomas Boutell. ; after last element was a bug.
   Examples of real world cookies that really work:
   Set-Cookie: MSNADS=UM=; domain=.slate.com;
         expires=Tue, 26-Apr-2022 19:00:00 GMT; path=/
   Set-Cookie: MC1=V=3&ID=b5bc08af2b8a43ff85fcb5efd8b238f0;
         domain=.slate.com; expires=Mon, 04-Oct-2021 19:00:00 GMT; path=/
*/

#if 0
void Cookie::Set(const string& name,
    const string& value,
    const int liveSeconds,
    const string& domain,
    const string& path)
{
    time_t now;
    time_t then;
    struct tm *gt;
    time(&now);
    then=now+liveSeconds;
    gt=gmtime(&then);
    fprintf(stdout,
        "Set-Cookie: %s=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n",
        name.c_str(), value.c_str(),
        days[gt->tm_wday],
        gt->tm_mday,
        months[gt->tm_mon],
        gt->tm_year + 1900,
        gt->tm_hour,
        gt->tm_min,
        gt->tm_sec,
        path.c_str());
}
#endif

void Cookie::Set(const string& name,
    const string& value,
    const string& extra)
{
    fprintf(stdout, "Set-Cookie: %s=%s; %s\r\n",
        name.c_str(), value.c_str(), extra.c_str());
}

KvVector::KvVector()
{

}

KvVector::KvVector(kvvector& prop)
{
    /*
    vector<struct kv>::iterator it;
    for (it = FormData.begin(); it != FormData.end(); it++)
    {
        cout << (*it).key << "=>" << (*it).value << endl;
    }
    */
    data_ = prop;
}

bool KvVector::Insert(const string& key, const string& value)
{
    struct rkv data;
    data.key = key;
    data.value = value;
    data_.push_back(data);
    return true;
}

bool KvVector::SetValue(const string& key, const string& value)
{
    int index;
    if (-1 != (index = Exist(key)))
    {
        data_[index].value = value;
        return true;
    }
    else
        return false;
}

bool KvVector::SetKey(int index, const string& key)
{
    data_[index].key = key;
    return true;
}

bool KvVector::SetValue(int index, const string& value)
{
    data_[index].value = value;
    return true;
}

bool KvVector::Erase(const string& key)
{
    int length = data_.size();
    int i = 0;
    while (i < length)
    {
        if (data_[i].key == key)
        {
            data_.erase(data_.begin() + i);
            length--;
        }
        else
        {
            i++;
        }
    }
    return true;
}

bool KvVector::Erase(int index)
{
    if (index >= Size())
        return false;
    else
    {
        data_.erase(data_.begin() + index);
        return true;
    }
}

int KvVector::Exist(const string& key)
{
    kvvector::iterator it;
    int i = 0;
    for (it = data_.begin(); it != data_.end(); it++, i++)
    {
        if ((*it).key == key)
        {
            return i;
        }
    }
    return -1;
}

string KvVector::GetKey(int index)
{
    return data_[index].key;
}

string KvVector::GetValue(int index)
{
    return data_[index].value;
}

string KvVector::GetValue(const string& key)
{
    kvvector::iterator it;
    for (it = data_.begin(); it != data_.end(); it++)
    {
        if ((*it).key == key)
        {
           return (*it).value;
        }
    }
    return "";
}

bool KvVector::Empty()
{
    if (data_.empty())
        return true;
    else
        return false;
}

void KvVector::Clear()
{
    data_.clear();
}

int KvVector::Size()
{
    return data_.size();
}

string KvVector::operator[](int index)
{
    if (index >= Size())
        return "";
    else
        return data_[index].value;
}

string KvVector::operator[](const string& key)
{
    kvvector::iterator it;
    for (it = data_.begin(); it != data_.end(); it++)
    {
        if ((*it).key == key)
        {
           return (*it).value;
        }
    }
    return "";
}

KvMap::KvMap()
{
    isConfig_ = false;
}

KvMap::KvMap(kvmap& prop)
{
    data_ = prop;
    isConfig_ = false;
}

void KvMap::ForConfig()
{
    isConfig_ = true;
}

void KvMap::ForGeneral()
{
    isConfig_ = false;
}

int KvMap::Size()
{
    return data_.size();
}

string KvMap::GetKey(int index)
{
    if (index >= Size())
        return "";
    kvmap::iterator it = data_.begin();
    for (int i = 0; i < index; i++)
    {
        it++;
    }
    return it->first;
}

string KvMap::GetValue(int index)
{
    if (index >= Size())
        return "";
    kvmap::iterator it = data_.begin();
    for (int i = 0; i < index; i++)
    {
        it++;
    }
    return it->second;
}

string KvMap::GetValue(const string& key)
{
    if (isConfig_)
    {
        kvmap::iterator it = data_.find(key);
        if (it != data_.end())
        {
            return it->second;
        }
        else
        {
            return "${" + key + "}";
        }
    }
    else
    {
        return data_[key];
    }
}

bool KvMap::Insert(const string& key, const string& value)
{
    data_[key] = value;
    return true;
}

bool KvMap::Erase(const string& key)
{
    kvmap::iterator it = data_.find(key);
    if (it != data_.end())
    {
        data_.erase(it);
        return true;
    }
    return false;
}

bool KvMap::Empty()
{
    if (data_.empty())
        return true;
    else
        return false;
}

void KvMap::Clear()
{
    data_.clear();
}

bool KvMap::Exist(const string& key)
{
    kvmap::iterator it = data_.find(key);
    if (it != data_.end())
    {
        return true;
    }
    else
    {
        return false;
    }
}

kvmap KvMap::Dump()
{
    return data_;
}

string KvMap::operator[](const string& key)
{
    return GetValue(key);
}

KvMap KvMap::StrSplit(const string& context,
    const string& str_delim,
    const string& kv_delim)
{
    //CGILOG(INFO);
    char* buf = NULL;
    char* kv = NULL;
    char* outer_ptr = NULL;
    char* inner_ptr = NULL;
    KvMap prop;

    if (context.empty())
    {
        return prop;
    }
    buf = (char*)context.c_str();
    while ((kv = CharSplit(buf, str_delim.c_str(), &outer_ptr)) != NULL)
    {
        char* key = NULL;
        char* value = NULL;

        if ((key = CharSplit(kv, kv_delim.c_str(), &inner_ptr)) != NULL)
        {
            if ((value = CharSplit(NULL, kv_delim.c_str(), &inner_ptr)) == NULL)
            {
                prop.Insert(key, "");
            }
            else
            {
                prop.Insert(key, value);
            }
        }
        buf = NULL;
    }
    //CGILOG(INFO);
    return prop;
}

FileVector::FileVector()
{

}

FileVector::FileVector(filevector& prop)
{
    data_ = prop;
}

int FileVector::Size()
{
    return data_.size();
}

bool FileVector::Insert(struct rfile& file)
{
    data_.push_back(file);
    return true;
}

bool FileVector::Erase(const string& key)
{
    filevector::iterator it;
    struct rfile file;
    for (it = data_.begin(); it != data_.end(); it++)
    {
        if ((*it).key == key)
        {
            file = (*it);
            if (file.key)
                free(file.key);
            if (file.name)
                free(file.name);
            if (file.type)
               free(file.type);
            if (file.data)
               free(file.data);
            file.size = 0;
            data_.erase(it);
            return true;
        }
    }
    return true;
}

struct rfile FileVector::operator[](int index)
{
    struct rfile file;
    file.key = NULL;
    file.name = NULL;
    file.type = NULL;
    file.data = NULL;
    file.size = 0;
    if (index >= Size())
        return file;
    return data_[index];
}

struct rfile FileVector::operator[](const string& key)
{
    filevector::iterator it;
    struct rfile file;
    file.key = NULL;
    file.name = NULL;
    file.type = NULL;
    file.data = NULL;
    file.size = 0;
    for (it = data_.begin(); it != data_.end(); it++)
    {
        if ((*it).key == key)
        {
           file = (*it);
           break;
        }
    }
    return file;
}

bool CppCgi::isCppCgiInited = false;

CppCgi::CppCgi()
{
    //CGILOG(INFO);
    if (isCppCgiInited)
        return;
    for (int i = 0; env[i] != ""; i++)
    {
        server.Insert(env[i], GetEnv(env[i]));
    }

    cookie = Cookie::Get();
    scriptName = SimplePath(GetEnv("SCRIPT_NAME"));
    string method = GetEnv("REQUEST_METHOD");
    string contentType = GetEnv("CONTENT_TYPE");
    string contentLen = GetEnv("CONTENT_LENGTH");
    CLOG(SYSTEM) << method
        << " " << GetEnv("REQUEST_URI")
        << " " << GetEnv("REMOTE_ADDR")
        << " " << GetEnv("HTTP_USER_AGENT") << endl;
    if (method == "GET")
    {
        get = KvVector::UrlSplit(GetEnv("QUERY_STRING"));
    }
    else if (method == "POST")
    {
        int length = atoi(contentLen.c_str());
        if (length > MAX_UPLOAD_LENGTH)
        {
            CLOG(ERROR) << "upload length " << length
                << " exceeds limit " << MAX_UPLOAD_LENGTH << endl;
            return;
        }
        char* buf = (char*)malloc(length + 1);
#ifdef WIN32
        _setmode(_fileno(stdin), _O_BINARY);
#endif
        int bufLen = 0;
        if (length < 0)
        {
            CLOG(ERROR) << "content-length:" << length << endl;
            return;
        }

#if 1
        bufLen = fread(buf, 1, length, stdin);
#else
        bufLen = ReadNoblock(stdin, buf, length, 1);
        if (bufLen == -1)
        {
            CLOG(ERROR) << "read timeout." << endl;
            return;
        }
#endif
        buf[length] = '\0';

        CLOG(INFO) << "length:" << length << " bufflen:" << bufLen << endl;

        if (contentType.find("multipart/form-data") != string::npos)
        {
            int pos = 0;
            pos = contentType.find("--");
            if (pos == string::npos)
            {
                error_code = 2012;
                return;
            }
            string boundry = contentType.substr(pos);
            boundry = "--" + boundry;
            int offset = 0;
            //CGICS << "buflen:" << bufLen << CGICE;
            while (offset < bufLen)
            {
                //CGICS << "offset:" << offset << CGICE;
                pos = FindMatch(buf + offset, boundry.c_str());
                if (pos >= 0)
                {
                    offset += pos;
                    offset += boundry.length();
                    offset += 2; // \r\n
                }

                pos = FindMatch(buf + offset, "Content-Disposition");
                if (pos >= 0)
                {
                    char* key = NULL;
                    char* value = NULL;
                    //char* type = NULL;
                    //char* data = NULL;
                    offset += pos;
                    offset += strlen("Content-Disposition: form-data;");
                    pos = FindMatch(buf + offset, "name");
                    if (pos >= 0)
                    {
                        offset += pos;
                        offset += strlen("name=\"");
                        pos = FindMatch(buf + offset, "\"");
                        if (pos < 0)
                        {
                            error_code = 2013;
                            return;
                        }
                        CopyChar(key, buf + offset, pos);
                        offset += pos;
                        offset += 1;
                    }
                    pos = FindMatch(buf + offset, "filename");
                    if (pos >= 0)
                    {
                        offset += pos;
                        offset += strlen("filename=\"");
                        pos = FindMatch(buf + offset, "\"");
                        if (pos < 0)
                        {
                            error_code = 2014;
                            return;
                        }
                        char* fileName = NULL;
                        CopyChar(fileName, buf + offset, pos);
                        string baseFileName = SimplePath(string(fileName));
                        if (fileName)
                            free(fileName);
                        CopyChar(value, baseFileName.c_str(), baseFileName.size());
                        offset += pos;
                        offset += 1;
                        offset += 2;

                        pos = FindMatch(buf + offset, "Content-Type");
                        if (pos >= 0)
                        {
                            offset += pos;
                            offset += strlen("Content-Type: "); // zhu yi hou mian you yi ge kong ge
                            pos = FindMatchAll(buf + offset, "\r\n\r\n", bufLen - offset);
                            if (pos < 0)
                            {
                                error_code = 2015;
                                return;
                            }
                            struct rfile upfile;
                            CopyChar(upfile.type, buf + offset, pos);
                            offset += pos;
                            offset += 4;    //\r\n\r\n

                            pos = FindMatchAll(buf + offset, boundry.c_str(), bufLen - offset);
                            if (pos < 2)
                            {
                                error_code = 2016;
                                return;
                            }
                            /* cha zhao dao =boundry shi you yi ge \r\n hun jin qu le */
                            CopyChar(upfile.data, buf + offset, pos - 2);
                            offset += pos;
                            upfile.name = value;
                            upfile.size = pos - 2;
                            upfile.key = key;
                            file.Insert(upfile);
                            //file.insert(std::pair<string, struct filemap>(key, upfile));
                            //CGICS << key << ":" << value << ":" << upfile.type << ":" << CGICE;
                        }
                    }
                    else
                    {
                        offset += 4;
                        pos = FindMatchAll(buf + offset, boundry.c_str(), bufLen - offset);
                        if (pos < 0)
                        {
                            error_code = 2017;
                            return;
                        }
                        CopyChar(value, buf + offset, pos - 2);
                        offset += pos;
                        // bu xu yao zhuan yi
                        post.Insert(key, value);
                        //CGICS << key << ":" << DecodeUrlComponent(value) << CGICE;
                    }
                }
                else
                {
                    break;
                }
            }
        }
        else
        {
            post = KvVector::UrlSplit(string(buf));
        }
        free(buf);
    }
    isCppCgiInited = true;
    //CGILOG(INFO);
}

CppCgi::~CppCgi()
{
    if (error_code != 0)
        CLOG(ERROR) << "initlized error:" << error_code << endl;
}

void CppCgi::Test()
{
    Test::Alert(get);
    Test::Alert(post);
    Test::Alert(server);
    Test::Alert(cookie);
    for (int i = 0; i < file.Size(); i++)
    {
        struct rfile tmpFile = file[i];
        CGICS << tmpFile.key << ": " << tmpFile.name << endl;
    }
}

File::File()
{

}

File::File(const string& fileName)
{
    if ((pstream_ = fopen(fileName.c_str(), "r")) == NULL)
    {
        CLOG(ERROR) << fileName << " fopen error:" << strerror(errno) << endl;
    }
}

File::File(FILE* stream)
{
    pstream_ = stream;
}

File::~File()
{
    Save();
}

File* File::Open(const string& fileName, const string& mode)
{
    //CGILOG(INFO);
    FILE* stream;
    if ((stream = fopen(fileName.c_str(), mode.c_str())) == NULL)
    {
        CLOG(ERROR) << fileName << " fopen error:" << strerror(errno) << endl;
        return NULL;
    }
    return new File(stream);
}

bool File::IsEmpty()
{
    if (pstream_)
    {
        return false;
    }
    else
    {
        return true;
    }
}

bool File::GetLine(string& line)
{
    //CGILOG(INFO);
    char* lineAsChar = NULL;
    size_t len = 0;
    ssize_t read;

    read = GetLineChar(&lineAsChar, &len, pstream_);
    if (read >= 0)
    {
        line = string(lineAsChar);
        free(lineAsChar);
        return true;
    }
    else
    {
        CLOG(ERROR) << "getline error:" << read << ":" << strerror(errno) << endl;
        return false;
    }
}
void File::AddLine(const string& s)
{
    //CGILOG(INFO);
    fwrite(s.c_str(), sizeof(char), s.length(), pstream_);
    fwrite("\n", 1, 1, pstream_);
}

void File::Write(const string& context)
{
    //CGILOG(INFO);
    fwrite(context.c_str(), sizeof(char), context.length(), pstream_);
}

void File::Save()
{
    //CGILOG(INFO);
    if (pstream_)
        fclose(pstream_);
}


ConfigSet::ConfigSet()
{

}

ConfigSet::ConfigSet(const string& fileName)
{
    fileName_ = fileName;
    LoadFromFile(fileName);
}

ConfigSet::~ConfigSet()
{

}

int ConfigSet::LoadFromFile(const string& fileName)
{
    ifstream ifs(fileName.c_str());
    if (!ifs)
    {
        fileExist_  = false;
        return 0;
    }

    fileExist_  = true;

    string line;
    string curTagName("");
    string lastTagName("");
    KvMap tempMap;
    ppair_.ForConfig();
    tempMap.ForConfig();
    while (getline(ifs, line))
    {
        Trim(line);
        //CLOG(ERROR) << line << endl;
        int len = line.length();
        if (len == 0)
        {
            continue;
        }
        //CGICS << line << CGICE;

        if (line.substr(0, 1) == "[" && line.substr(len - 1, 1) == "]")
        {
            ////CGILOG(INFO);
            curTagName = line.substr(1, len - 2);
            if (curTagName != lastTagName)
            {
                if (!lastTagName.empty())
                {
                    ////CGILOG(INFO);
                    pgroup_.insert(std::pair<string, KvMap>(lastTagName, ppair_));
                }
                else
                {
                    /**
                     * ru guo di yi zu mei you zu ming, jiu bao cun qi lai
                     */
                    tempMap = ppair_;
                }
                ppair_.Clear();
                lastTagName = curTagName;
            }
        }
        else if (line.substr(0, 1) == ";" || line.substr(0, 1) == "#")
        {
            continue;
        }
        else
        {
            size_t pos = line.find("=");
            if (pos != string::npos)
            {
                string key = line.substr(0, pos);
                string value = line.substr(pos + 1);
                Trim(key);
                Trim(value);
                //CGICS << key << CGICE;
                //CGICS << value << CGICE;

                ppair_.Insert(key, value);
            }
        }
    }
    /**
     * zui hou yi zu hai mei chu li
     */
    if (!lastTagName.empty())
    {
        ////CGILOG(INFO);
        pgroup_.insert(std::pair<string, KvMap>(lastTagName, ppair_));
        ppair_ = tempMap;
    }
    //CGILOG(INFO);
    return 0;
}

void ConfigSet::Insert(const string& key, const string& value)
{
    ppair_.Insert(key, value);
}

void ConfigSet::Insert(KvMap& input)
{
    ppair_ = input;
}

void ConfigSet::MInsert(const string& gname, KvMap& pair)
{
    pgroup_[gname] = pair;
}

void ConfigSet::MInsert(const string& gname, const string& key, const string& value)
{
    pgroup_[gname].Insert(key, value);
}

void ConfigSet::MDelet(const string& gname)
{
    pgroup_.erase(gname);
}

bool ConfigSet::Empty()
{
    if (ppair_.Empty() && pgroup_.empty())
        return true;
    else
        return false;
}

bool ConfigSet::Clear()
{
    ppair_.Clear();
    pgroup_.clear();
    return true;
}

int ConfigSet::Size()
{
    return pgroup_.size();
}

KvMap ConfigSet::GetKv()
{
    return ppair_;
}

string ConfigSet::GetKey(int index)
{
    if (index >= Size())
        return "";
    mKvMap::iterator it = pgroup_.begin();
    for (int i = 0; i < index; i++)
    {
        it++;
    }
    return it->first;
}

void ConfigSet::Test()
{
    Test::Alert(ppair_);

    mKvMap::iterator it;
    for (it = pgroup_.begin(); it != pgroup_.end(); it++)
    {
        CGICS << "[" << it->first << "]" << CGICE;
        Test::Alert(it->second);
    }
}

int ConfigSet::SaveToFile(const string& fileName)
{
    //CGILOG(INFO);
    string context;
    kvmap ppair = ppair_.Dump();
    for (kvmap::iterator it = ppair.begin(); it != ppair.end(); it++)
    {
        context += it->first + " = " + it->second + "\r\n";
    }

    for (mKvMap::iterator its = pgroup_.begin(); its != pgroup_.end(); its++)
    {
        context += "[" + its->first + "]\r\n";

        kvmap pair = (its->second).Dump();

        for (kvmap::iterator it = pair.begin(); it != pair.end(); it++)
        {
            context += it->first + " = " + it->second + "\r\n";
        }
    }

    File* file = File::Open(fileName, "w");
    if (file == NULL)
        return -1;
    else
    {
        //fang zhi lu jing cuo wu dao zhi chuang jian shi bai
        file->Write(context);
        file->Save();
        return 0;
    }

    //CGILOG(INFO);
}

void ConfigSet::Save()
{
    SaveToFile(fileName_);
}

KvMap ConfigSet::operator[](const string& gname)
{
    mKvMap::iterator it = pgroup_.find(gname);
    if (it != pgroup_.end())
    {
        return it->second;
    }
    else
    {
        KvMap blank;
        return blank;
    }
}

ConfigSet ConfigSet::ConfigSetSplit(KvVector& input, const string& keyDelim)
{
    string currentKey;
    string currentValue;
    string lastPartName("");
    ConfigSet output;
    KvMap collectMap;

    int len = input.Size();
    for (int i = 0; i < len; i++)
    {
        currentKey = input.GetKey(i);
        currentValue = input.GetValue(i);
        if (currentKey.empty())
            continue;

        int pos = currentKey.find(keyDelim);
        if (pos != string::npos)
        {
            if (currentValue != lastPartName)
            {
                if (!lastPartName.empty())
                    output.MInsert(lastPartName, collectMap);
                else
                    output.Insert(collectMap);

                collectMap.Clear();
                lastPartName = currentValue;
            }
        }
        else
        {
            collectMap.Insert(currentKey, currentValue);
        }
    }
    /**
     * zui hou yi zu hai mei chu li
     */
    if (!lastPartName.empty())
        output.MInsert(lastPartName, collectMap);

    return output;
}

OrderedConfigSet::OrderedConfigSet()
{

}

OrderedConfigSet::OrderedConfigSet(const string& fileName)
{
    fileName_ = fileName;
    LoadFromFile(fileName);
}

OrderedConfigSet::~OrderedConfigSet()
{

}

int OrderedConfigSet::LoadFromFile(const string& fileName)
{
    ifstream ifs(fileName.c_str());
    if (!ifs)
    {
        fileExist_  = false;
        return 0;
    }

    fileExist_  = true;

    string line;
    string curTagName("");
    string lastTagName("");
    KvVector tempMap;
    while (getline(ifs, line))
    {
        Trim(line);
        //CLOG(ERROR) << line << endl;
        int len = line.length();
        if (len == 0)
        {
            continue;
        }
        //CGICS << line << CGICE;

        if (line.substr(0, 1) == "[" && line.substr(len - 1, 1) == "]")
        {
            ////CGILOG(INFO);
            curTagName = line.substr(1, len - 2);
            if (curTagName != lastTagName)
            {
                if (!lastTagName.empty())
                {
                    ////CGILOG(INFO);
                    pgroup_.insert(std::pair<string, KvVector>(lastTagName, ppair_));
                }
                else
                {
                    /**
                     * ru guo di yi zu mei you zu ming, jiu bao cun qi lai
                     */
                    tempMap = ppair_;
                }
                ppair_.Clear();
                lastTagName = curTagName;
            }
        }
        else if (line.substr(0, 1) == ";" || line.substr(0, 1) == "#")
        {
            continue;
        }
        else
        {
            size_t pos = line.find("=");
            if (pos != string::npos)
            {
                string key = line.substr(0, pos);
                string value = line.substr(pos + 1);
                Trim(key);
                Trim(value);
                //CGICS << key << CGICE;
                //CGICS << value << CGICE;

                ppair_.Insert(key, value);
            }
        }
    }
    /**
     * zui hou yi zu hai mei chu li
     */
    if (!lastTagName.empty())
    {
        ////CGILOG(INFO);
        pgroup_.insert(std::pair<string, KvVector>(lastTagName, ppair_));
        ppair_ = tempMap;
    }
    //CGILOG(INFO);
    return 0;
}

void OrderedConfigSet::Insert(const string& key, const string& value)
{
    ppair_.Insert(key, value);
}

void OrderedConfigSet::Insert(KvVector& input)
{
    ppair_ = input;
}

void OrderedConfigSet::MInsert(const string& gname, KvVector& pair)
{
    pgroup_[gname] = pair;
}

void OrderedConfigSet::MInsert(const string& gname, const string& key, const string& value)
{
    pgroup_[gname].Insert(key, value);
}

void OrderedConfigSet::MDelet(const string& gname)
{
    pgroup_.erase(gname);
}

bool OrderedConfigSet::Empty()
{
    if (ppair_.Empty() && pgroup_.empty())
        return true;
    else
        return false;
}

bool OrderedConfigSet::Clear()
{
    ppair_.Clear();
    pgroup_.clear();
    return true;
}

int OrderedConfigSet::Size()
{
    return pgroup_.size();
}

KvVector OrderedConfigSet::GetKv()
{
    return ppair_;
}

string OrderedConfigSet::GetKey(int index)
{
    if (index >= Size())
        return "";
    kVectorMap::iterator it = pgroup_.begin();
    for (int i = 0; i < index; i++)
    {
        it++;
    }
    return it->first;
}

void OrderedConfigSet::Test()
{
    Test::Alert(ppair_);

    kVectorMap::iterator it;
    for (it = pgroup_.begin(); it != pgroup_.end(); it++)
    {
        CGICS << "[" << it->first << "]" << CGICE;
        Test::Alert(it->second);
    }
}

int OrderedConfigSet::SaveToFile(const string& fileName)
{
    //CGILOG(INFO);
    string context;
    for (int i = 0; i < ppair_.Size(); i++)
        context += ppair_.GetKey(i) + " = " + ppair_.GetValue(i) + "\r\n";

    for (kVectorMap::iterator its = pgroup_.begin(); its != pgroup_.end(); its++)
    {
        context += "[" + its->first + "]\r\n";

        KvVector ppair = its->second;

        for (int i = 0; i < ppair.Size(); i++)
            context += ppair.GetKey(i) + " = " + ppair.GetValue(i) + "\r\n";
    }

    File* file = File::Open(fileName, "w");
    if (file == NULL)
        return -1;
    else
    {
        //fang zhi lu jing cuo wu dao zhi chuang jian shi bai
        file->Write(context);
        file->Save();
        return 0;
    }

    //CGILOG(INFO);
}

void OrderedConfigSet::Save()
{
    SaveToFile(fileName_);
}

KvVector OrderedConfigSet::operator[](const string& gname)
{
    kVectorMap::iterator it = pgroup_.find(gname);
    if (it != pgroup_.end())
    {
        return it->second;
    }
    else
    {
        KvVector blank;
        return blank;
    }
}

void Test::Alert(const string& str)
{
    CGICS << str << CGICE;
    CGICS << "---" << CGICE;
}

void Test::Alert(kvmap& prop)
{
    for (kvmap::iterator it = prop.begin(); it != prop.end(); it++)
    {
        CGICS << it->first << "=>" << it->second << CGICE;
    }
    CGICS << "---" << CGICE;
}

void Test::Alert(KvMap& prop)
{
    kvmap temp = prop.Dump();
    Test::Alert(temp);
}

void Test::Alert(KvVector& prop)
{
    int i, len;
    len = prop.Size();
    for (i = 0; i < len; i++)
    {
        CGICS << prop.GetKey(i) << "=>" << prop.GetValue(i) << CGICE;
    }
    CGICS << "---" << CGICE;
}

void Test::Show(const char* str, int len, const char* format)
{
    int i = 0;
    for (i = 0; i < len; i++)
    {
        fprintf(CGIOUTS, format, (unsigned char)str[i]);
        if (i % 16 == 15)
        {
            fprintf(CGIOUTS, CGIENTER);
        }
        else
        {
            fprintf(CGIOUTS, CGIBLANK);
        }
    }
    fprintf(CGIOUTS, CGIENTER);
    CGICS << "---" << CGICE;
}

LogMessage::LogMessage(const char* mask)
{
    fileobj_.open(CGILOGFILE, ios::app);
    fileobj_ << mask << " "
             << GetFormatTime() << " ";
}

LogMessage::LogMessage(const char* mask, int id)
{
    fileobj_.open(CGILOGFILE, ios::app);
    fileobj_ << mask << " "
             << GetFormatTime() << " "
             << (scriptName == "" ? "(" : (scriptName + "("))
             << id << ") ";
}

LogMessage::LogMessage(const char* mask, const char* file, int line)
{
    fileobj_.open(CGILOGFILE, ios::app);
    fileobj_ << mask << " "
             << GetFormatTime() << " "
             << (scriptName == "" ? "" : (scriptName + " "))
             << file << ":" << line << "] ";
}

LogMessage::~LogMessage()
{
    fileobj_.close();
}

ofstream& LogMessage::Stream()
{
    return fileobj_;
}

CIntStr::CIntStr(int num)
{
    stringstream _z;
    _z << num;
    try
    {
        _z >> num_;
    }
    catch(...)
    {
        num_ = "0";
    }
}

CIntStr::CIntStr(uint32_t num, bool x)
{
    stringstream _z;
    _z << num;
    try
    {
        _z >> num_;
    }
    catch(...)
    {
        num_ = "0";
    }
}

CIntStr::CIntStr(const string num)
{
    num_ = num;
}

string CIntStr::ToString()
{
    return num_;
}

int CIntStr::ToInt()
{
    stringstream _z;
    int ret = 0;
    _z << num_;
    try
    {
        _z >> ret;
    }
    catch(...)
    {

    }
    return ret;
}

uint32_t CIntStr::ToUint()
{
    stringstream _z;
    uint32_t ret = 0;
    _z << num_;
    try
    {
        _z >> ret;
    }
    catch(...)
    {

    }
    return ret;
}

#ifdef __posix
CRegex::CRegex(const string& regexSrc)
{
    int ret;
    int bufLen;
    char* buf = NULL;
    nmatch_ = REGEX_SUBSTRING_SIZE;
    pmatch_ = new regmatch_t[REGEX_SUBSTRING_SIZE];
    ret = regcomp(&regexObj_, regexSrc.c_str(), REG_EXTENDED);
    /*
    bufLen = regerror(ret, &regexObj_, NULL, 0);
    buf = (char*)malloc(bufLen + 1);
    regerror(ret, &regexObj_, buf, bufLen);
    buf[bufLen] = '\0';
    errmsg_ = string(buf);
    free(buf);
    */
}

CRegex::~CRegex()
{
    delete []pmatch_;
    regfree(&regexObj_);
}

bool CRegex::Match(const string& str)
{
    int ret;
    objstring_ = str;
    ret = regexec(&regexObj_, str.c_str(), nmatch_, pmatch_, REG_NOTEOL);
    if (ret == REG_NOMATCH)
        return false;
    else
    {
        //str = str.substr(pmatch_[0].rm_so, pmatch_[0].rm_eo - pmatch_[0].rm_so);
        return true;
    }
}

string CRegex::GetMatchStr(int index)
{
    if (index > REGEX_SUBSTRING_SIZE)
        return "";
    return objstring_.substr(pmatch_[index].rm_so, pmatch_[index].rm_eo - pmatch_[index].rm_so);
}
#endif
/**
 * [key and value is the same?]
 * @param  str   [description]
 * @param  delim [description]
 * @return       [description]
 */
KvVector KvVector::Split(const string str, const string delim)
{
    KvVector strsplits;
    size_t pos = 0;
    size_t lastpos = 0;
    size_t delimLen = delim.size();
    string tmp;
    while ((pos = str.find(delim.c_str(), lastpos, delimLen)) != string::npos)
    {
        tmp = str.substr(lastpos, pos - lastpos);
        lastpos = pos + delimLen;
        strsplits.Insert(tmp, tmp);
    }
    tmp = str.substr(lastpos, str.size() - lastpos);
    strsplits.Insert(tmp, tmp);
    return strsplits;
}

#ifdef __posix

/*
int ReadNoblock(FILE *fp, char *buf, int size, int ms)
{
    int flags, oldflags;
    int fdno = fileno(fp);
    int ret = -1;
    oldflags = flags = fcntl(fdno, F_GETFL);
    flags |= O_NONBLOCK;
    if (fcntl(fdno, F_SETFL, flags) == -1)
    {
        CLOG(ERROR) << "set nonblock fcntl:" << strerror(errno) << endl;
        return -1;
    }
    int timeout = ms;
    int toread = size;
    char *pbuf = buf;
    do
    {
        int n = read(fdno, pbuf, toread);
        int err = errno;
        if (n >= 0)
        {
            ret = 1;
            toread -= n;
            pbuf += n;
            if (toread == 0)
                break;
            continue;
        }
        else
        {
            if (err != EAGAIN)
                break;
        }
        usleep(1000);
    } while (timeout-->0);

    if (fcntl(fdno, F_SETFL, oldflags) == -1)
    {
        CLOG(ERROR) << "reset nonblock fcntl:" << strerror(errno) << endl;
    }

    return ret == -1 ? ret : (pbuf - buf);
}
*/
#endif

}   //namespace cppcgi
